'use strict';  

/** 
 * 观察者模式  
 **/ 
export class Observer {
    constructor (){

        /**
         * 事件队列
         * stack 结构
         * {
         *   [Event Name]: {
         *      'Handler ID': Handler Function 
         *   }
         * 
         *   // eg
         *   load: {
         *      0: function () {console.log(1);}
         *   }
         * }
         **/
        this.stack = {};
    }

     /**
     * 监听
     * 
     * @param {string[number]} type 事件类型
     * @param {function} args 传递给该事件的处理函数，一个事件可以一次对应多个处理函数，多个处理函数时形成一个事件处理流 
     */ 
    on (type, ...args) {
        // 松散，只为阅读性
        switch (typeof type){
            case 'number':
            case 'string': temp.call(this); break;
            default: break;
        }

        function temp(){
            // __ID__ 标识处理函数
            const { stack } = this;

            stack[type] = stack[type] || { __ID__: 0 }; 
            const handlerMap = stack[type];

            for (let i = 0, max = args.length; i < max; i++) {
                const handler = args[i];
                if ('function' === typeof handler) { 
                    // 去重，避免同一事件多次绑定
                    if (!handler.__ID__) {
                        handler.__ID__ = ++handlerMap.__ID__;
                        handlerMap[handler.__ID__] = handler;
                    }
                }else {
                    // 确保handler是函数
                    throw new TypeError('The event handler must be a function.');
                }
            }
        }
    }

    /**
     * 触发
     * 
     * @param {string[number]} type 事件类型  
     * @param {*} args[n] 传递给每个handler的参数(n为大于0的整数)
     */ 
    emit(type, ...args){
        switch (typeof type){
            case 'number':
            case 'string': 
            {
                const handlerMap = this.stack[type]; 
                for (const handlerId in handlerMap) {
                    const handler = handlerMap[handlerId];
                    if ('function' === typeof handler) {
                        handler(...args);
                    }
                }
            }
            break;
            default: break;
        }
    }

    /**
     * 关闭
     * @param {string[number]} type 事件类型
     * @param {function} callback 关闭事件之后的回调函数 
     */ 
    off(type, handlerId, callback){
        switch (typeof type){
            case 'number':
            case 'string': 
            {
                if (Reflect.has(this.stack, type)) {
                    Reflect.deleteProperty(this.stack,type);
                    'function' === typeof callback && callback();
                }
            }
            break;
            case 'function':
            {
                callback = type;
                this.stack = {};
                callback();
            }
            break;
            default: break;
        } 
        return this;
    }

    /**
     * 一次性监听，触发之后立即被off
     * @param {string[number]} type 事件类型
     * @param {function} handler 传递给该事件的处理函数
     * @param {*} args 传递给该事件的处理函数的参数
     */ 
    once(type, handler, ...args){ 
        switch (typeof type){
            case 'number':
            case 'string':
            {   
                if ('function' === typeof handler) {
                    const stack = this.stack;
                    stack[type] = stack[type] || { __ID__: 0 }; 
                    const handlerMap = stack[type]; 
                    const handlerIds = ++handlerMap.__ID__;
                    function once() {
                        handler(...args);
                        if (handlerIds > 1) { 
                            Reflect.deleteProperty(handlerMap, handlerIds);
                        }else { 
                            Reflect.deleteProperty(stack,type);
                        }
                    };
                    once.__ID__ = handlerIds;
                    handlerMap[handlerIds] = once; 
                }    
            }   
            break;
            default: break;
        }
        return this;
    }
}
